#pragma once

#include <jsoncpp/json/json.h>
#include <string>

#include "../Comm/Log.hpp"
#include "../Comm/Tool.hpp"
#include "Complier.hpp"
#include "Runner.hpp"

namespace Compile_Run_NS
{
    using namespace Tool_NS;
    using namespace Log_NS;
    using namespace Compiler_NS;
    using namespace Runner_NS;

    class Compile_Run
    {
    public:
        /*************************************************************
         * 将状态代码转化为字符串描述
         * status < 0 : 发生非运行错误
         * status > 0 : 程序运行错误，收到信号
         * status = 0 : 代码编译运行成功
        **************************************************************/

        // 这里的file_name是用来特殊处理-3的，也就是编译出错，需要读取到编译错误的原因
        static std::string StatusToDesc(int status,const std::string& file_name)
        {
            std::string desc;

            switch (status)
            {
            case 0:
                desc = "Compilation and execution are successful.";  // 编译运行成功
                break;
            case -1:
                desc = "Submitted code is empty";  // 提交代码为空
                break;
            case -2:
                desc = "An unknown error has occurred"; // 发生未知错误
                break;
            case -3:
                FileTool::ReadFile(PathTool::CompileError(file_name),&desc);
                break;
            case 6:  // SIGABRT --> 6号信号
                desc = "Exceed the memory usage limit";  // 超过内存使用上限
                break;
            case 24: // SIGXCPU --> 24号信号
                desc = "Exceeding the CPU usage limit";  // 超过CPU使用上限
                break;
            default:
                // desc = "未知 : " + std::to_string(status);
                desc = "Unknown : " + std::to_string(status);
                break;
            }
            return desc;
        }

        // 这里删除临时文件的个数我们不确定，但是有哪些临时文件我们是知道的
        static void RemoveTempFile(const std::string& file_name)
        {
            if(FileTool::IsFileExists(PathTool::Src(file_name)))
                unlink(PathTool::Src(file_name).c_str());

            if(FileTool::IsFileExists(PathTool::Exe(file_name)))
                unlink(PathTool::Exe(file_name).c_str());
            
            if(FileTool::IsFileExists(PathTool::CompileError(file_name)))
                unlink(PathTool::CompileError(file_name).c_str());

            if(FileTool::IsFileExists(PathTool::Stdin(file_name)))
                unlink(PathTool::Stdin(file_name).c_str());

            if(FileTool::IsFileExists(PathTool::Stdout(file_name)))
                unlink(PathTool::Stdout(file_name).c_str());

            if(FileTool::IsFileExists(PathTool::Stderr(file_name)))
                unlink(PathTool::Stderr(file_name).c_str());
        }
        /*************************************************************
         * 输入：in_json
         *  code：用户提交的代码
         *  input：用户提交代码对应的信息，这里不做处理
         *  cpu_limit：时间限制
         *  mem_limit：空间限制
         * 输出：out_json
         * 输出必填：
         *  status：状态码
         *  reason：若程序出错，对应出错的原因
         * 输出选填：
         *  stdout：程序运行结果
         *  stderr：程序运行错误，错误的原因
         * in_json --> {"code":"用户代码","input":"用户输入","cpu_limit":"时间上限值","mem_limit":"空间上限值(KB)"}
         * out_json --> {"status":"状态码","reason":"出错原因","stdout":"运行结果","stderr":"错误原因)"}
         ************************************************************/
        static void Start(const std::string &in_json, std::string *out_json)
        {
            Json::Value in_str;
            Json::Reader reader;
            reader.parse(in_json, in_str);

            // 提取上层发送的各种信息，反序列化
            std::string code = in_str["code"].asString();
            std::string input = in_str["input"].asString();
            int cpu_limit = in_str["cpu_limit"].asInt();
            int mem_limit = in_str["mem_limit"].asInt();

            Json::Value out_str;
            Json::FastWriter writer;

            int code_status = 0; // 代码状态
            int run_status = 0;  // 可执行程序运行状态

            // 这里获取的文件名不包含路径和后缀
            std::string file_name = FileTool::UniqFileName();

            if (code.size() == 0)
            {
                code_status = -1; // 用户提供代码为空
                goto END;
                // out_str["status"] = -1; // 用户提供代码为空
                // out_str["reason"] = "提供代码为空";
            }

            if (!FileTool::WriteFile(PathTool::Src(file_name), code)) // 将代码写入到源文件中
            {
                code_status = -2; // 将文件写入源文件失败
                goto END;

                // out_str["status"] = -2; // 将文件写入源文件失败
                // out_str["reason"] = "未知错误";
            }

            if (!Compiler::Compile(file_name)) // 编译源文件
            {
                code_status = -3; // 编译源文件失败
                goto END;

                // out_str["status"] = -3; // 编译源文件失败
                // out_str["reason"] = "未知错误";
            }

            run_status = Runner::Run(file_name, cpu_limit, mem_limit); // 执行可执行程序
            if (run_status < 0)
            {
                code_status = -2; // Run 发生了内部错误（临时文件打开失败、创建子进程失败等）
                // out_str["status"] = -2; // Run 发生了内部错误（临时文件打开失败、创建子进程失败等）
                // out_str["reason"] = "未知错误";
            }
            else if (run_status > 0)
            {
                code_status = run_status; // 运行可执行程序发生错误
                // out_str["status"] = run_status; // 运行可执行程序发生错误
                // out_str["reason"] = "..."; // 程序获取到信号的对应信息
            }
            else // run_status == 0
            {
                code_status = run_status; // 运行可执行程序成功

                // out_str["status"] = run_status; // 运行可执行程序成功
                // out_str["reason"] = "运行成功";
            }

        END:
            out_str["status"] = code_status;
            out_str["reason"] = StatusToDesc(code_status,file_name);

            // 程序编译运行成功
            if (code_status == 0)
            {
                std::string stdout_str;
                std::string stderr_str;

                FileTool::ReadFile(PathTool::Stdout(file_name), &stdout_str);
                FileTool::ReadFile(PathTool::Stderr(file_name), &stderr_str);

                out_str["stdout"] = stdout_str;
                out_str["stderr"] = stderr_str;
            }

            // 序列化
            *out_json = writer.write(out_str);

            // 删除所有临时文件
            RemoveTempFile(file_name);
        }
    };
}
